package com.bmps.springcloud.insuredmicroservice.util.accept;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bmps.springcloud.common.utils.DateUtil;
import com.bmps.springcloud.common.utils.IDCardCheck;
import com.bmps.springcloud.insuredmicroservice.constant.accept.AcceptConstant;
import com.bmps.springcloud.insuredmicroservice.constant.accept.AgencyConstant;
import com.bmps.springcloud.insuredmicroservice.constant.accept.StrategyConstant;
import com.bmps.springcloud.insuredmicroservice.constant.accept.UnderWriteConstant;
import com.bmps.springcloud.insuredmicroservice.model.accept.MessageModel;
import com.bmps.springcloud.insuredmicroservice.model.accept.PersonModel;
import com.bmps.springcloud.insuredmicroservice.model.accept.response.*;
import com.bmps.springcloud.insuredmicroservice.model.accept.resquest.*;
import com.bmps.springcloud.insuredmicroservice.model.underwrite.InsuredModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.NonNull;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Date;
import java.util.List;

/**
 * @author lyw
 * @date 2019/07/24
 */
@Slf4j
public class AcceptUtil {
    public static void setPersonModelIdNo(PersonModel personModel) {
        String idNo = personModel.getIdNo();
        if (StringUtils.equals(AcceptConstant.CREDENTIALS_IDNO, personModel.getIdType())
                && IDCardCheck.checkIDCard(idNo)) {
            if (idNo.length() == AcceptConstant.IDENTITY_CARD_18) {
                personModel.setIdNo18(idNo);
                personModel.setIdNoLower18(idNo.toLowerCase());
                personModel.setIdNoUpper18(idNo.toUpperCase());
                String idno = IDCardCheck.turnTo15(personModel.getIdNo());
                personModel.setIdNo15(idno);
                personModel.setIdNoLower15(idno.toLowerCase());
                personModel.setIdNoUpper15(idno.toUpperCase());
            } else {
                personModel.setIdNo15(idNo);
                personModel.setIdNoLower15(idNo.toLowerCase());
                personModel.setIdNoUpper15(idNo.toUpperCase());
                String idno = IDCardCheck.turnTo18(idNo);
                personModel.setIdNo18(idno);
                personModel.setIdNoLower18(idno.toLowerCase());
                personModel.setIdNoUpper18(idno.toUpperCase());
            }
        } else {
            personModel.setIdNo15(idNo);
            personModel.setIdNoLower15(idNo);
            personModel.setIdNoUpper15(idNo);
            personModel.setIdNo18(idNo);
            personModel.setIdNoLower18(idNo);
            personModel.setIdNoUpper18(idNo);
        }
    }

    public static boolean isSamePerson(AppntModel appntModel, PersonModel personModel) {
        String appBirthday = DateUtil.format(appntModel.getAppntBirthday(), "yyyy-MM-dd");
        return (StringUtils.equals(appntModel.getAppntName(), personModel.getName())
                && StringUtils.equals(appntModel.getAppntSex(), personModel.getSex())
                && StringUtils.equals(appBirthday, personModel.getBirthday())
                && StringUtils.equals(appntModel.getIdNo(), personModel.getIdNo())
                && StringUtils.equals(appntModel.getIdType(), personModel.getIdType()));
    }

    public static boolean isSamePerson(InsurantModel insurantModel, PersonModel personModel) {
        String insBirthday = DateUtil.format(insurantModel.getBirthday(), "yyyy-MM-dd");
        return (StringUtils.equals(insurantModel.getName(), personModel.getName())
                && StringUtils.equals(insurantModel.getSex(), personModel.getSex())
                && StringUtils.equals(insBirthday, personModel.getBirthday())
                && StringUtils.equals(insurantModel.getIdNo(), personModel.getIdNo())
                && StringUtils.equals(insurantModel.getIdType(), personModel.getIdType()));
    }
    public static boolean isSamePerson(BeneficiaryModel beneficiaryModel, PersonModel personModel){
        String bfcyBirthday = DateUtil.format(beneficiaryModel.getBfcyBirthday(), "yyyy-MM-dd");
        return (StringUtils.equals(beneficiaryModel.getBfcyName(), personModel.getName())
                && StringUtils.equals(beneficiaryModel.getBfcySex(), personModel.getSex())
                && StringUtils.equals(bfcyBirthday, personModel.getBirthday())
                && StringUtils.equals(beneficiaryModel.getBfcyIdCode(), personModel.getIdNo())
                && StringUtils.equals(beneficiaryModel.getBfcyIdType(), personModel.getIdType()));
    }

    public static MessageModel getMessage(AcceptResponseDataModel acceptResponseDataModel, String contNo) {
        MessageModel messageModel = new MessageModel();
        ResponseHeaderModel header = acceptResponseDataModel.getHeader();
        messageModel.setRequestType(header.getRequestType());
        messageModel.setUuid(header.getUUID());
        messageModel.setSendTime(header.getSendTime());
        messageModel.setSourceId("");
        messageModel.setContNo(contNo);
        messageModel.setResponse(JSON.toJSONString(acceptResponseDataModel));
        if (StringUtils.equals(AcceptConstant.RESPONSE_ERROR_CODE, header.getResponseCode())) {
            messageModel.setDescription(JSON.toJSONString(header.getErrorList()));
            messageModel.setState(AcceptConstant.MESSAGE_FAIL_CODE);
        } else {
            messageModel.setDescription(JSON.toJSONString(acceptResponseDataModel.getResponse().getResult()));
            if (StringUtils.equals(AcceptConstant.CLOUD_UNDERWRITE_CODE, acceptResponseDataModel.getResponse().getResult().getResultCode())) {
                messageModel.setState(AcceptConstant.MESSAGE_SUCCESS_CODE_ONE);
            } else if (StringUtils.equals(AcceptConstant.CLOUD_PERSON_UNDERWRITE_CODE, acceptResponseDataModel.getResponse().getResult().getResultCode())) {
                messageModel.setState(AcceptConstant.MESSAGE_SUCCESS_CODE_TWO);
            } else {
                messageModel.setState(AcceptConstant.MESSAGE_FAIL_CODE);
            }
        }
        return messageModel;
    }

    public static InsuredModel getInsuredResponse(String resultCode, String resultMessage) {
        InsuredModel insuredModel = new InsuredModel();
        insuredModel.setResultCode(resultCode);
        insuredModel.setResultMessage(resultMessage);
        return insuredModel;
    }

    public static InsuredModel getInsuredResponse(String resultCode, String resultMessage, BigDecimal sum) {
        InsuredModel insuredModel = new InsuredModel();
        insuredModel.setResultCode(resultCode);
        insuredModel.setResultMessage(resultMessage);
        insuredModel.setSum(sum);
        return insuredModel;
    }

    public static int compareTo(BigDecimal b1, BigDecimal b2) {
        return b1.compareTo(b2);
    }

    /**
     * 构造返回对象
     *
     * @param requestHeaderModel       请求头对象
     * @param resultModel              提示信息对象
     * @param responseProductInfoModel 产品对象
     * @return AcceptResponseDataModel
     */
    public static AcceptResponseDataModel getResponseResult(RequestHeaderModel requestHeaderModel,
                                                            ResultModel resultModel, ResponseProductInfoModel responseProductInfoModel) {
        AcceptResponseDataModel acceptResponseDataModel = new AcceptResponseDataModel();
        ResponseHeaderModel responseHeaderModel = new ResponseHeaderModel();
        responseHeaderModel.setRequestType(requestHeaderModel.getRequestType());
        responseHeaderModel.setUUID(requestHeaderModel.getUUID());
        responseHeaderModel.setSendTime(requestHeaderModel.getSendTime());
        responseHeaderModel.setResponseCode(AcceptConstant.RESPONSE_SUCCESS_CODE);
        acceptResponseDataModel.setHeader(responseHeaderModel);
        ResponseModel responseModel = new ResponseModel();
        responseModel.setResult(resultModel);
        responseModel.setProductInfo(responseProductInfoModel);
        acceptResponseDataModel.setResponse(responseModel);
        return acceptResponseDataModel;
    }

    /**
     * 重复保单受理返回结果
     *
     * @param requestHeaderModel 请求报文头
     * @return AcceptResponseDataModel
     */
    public static AcceptResponseDataModel getDuplicateResponseResult(RequestHeaderModel requestHeaderModel) {
        AcceptResponseDataModel acceptResponseDataModel = new AcceptResponseDataModel();
        ResponseHeaderModel responseHeaderModel = new ResponseHeaderModel();
        responseHeaderModel.setUUID(requestHeaderModel.getUUID());
        responseHeaderModel.setSendTime(requestHeaderModel.getSendTime());
        responseHeaderModel.setRequestType(requestHeaderModel.getRequestType());
        responseHeaderModel.setResponseCode(AcceptConstant.RESPONSE_SUCCESS_CODE);
        acceptResponseDataModel.setHeader(responseHeaderModel);
        ResultModel resultModel = new ResultModel();
        resultModel.setResultCode(AcceptConstant.RESULT_FAIL_CODE);
        resultModel.setResultMessage(UnderWriteConstant.UNDER_WRITE_REPEAT);
        ResponseModel responseModel = new ResponseModel();
        responseModel.setResult(resultModel);
        acceptResponseDataModel.setResponse(responseModel);
        return acceptResponseDataModel;
    }


    /**
     * 计算累积风险保额
     *
     * @param riskCode 险种
     * @param amnt     保额
     * @return 风险保额
     */
    public static BigDecimal sumInsured(String riskCode, BigDecimal amnt) {
        if (StringUtils.equals(AcceptConstant.PRODUCT_RISKCODE_HDT053, riskCode)) {
            return amnt.multiply(BigDecimal.valueOf(0.2));
        }
        return amnt;
    }

    /**
     * 权限flag=2^n 如果permission包含flag权限返回true
     *
     * @param flag       权限
     * @param permission 被判断数
     * @return boolean
     */
    public static boolean isRiskType(int flag, int permission) {
        return flag == (flag & permission);
    }

    public static boolean isStrategy(int strategy, String riskCode, List<String> riskStrategies) {
        for (String riskStrategy : riskStrategies) {
            if (riskStrategy.contains(riskCode)) {
                return isRiskType(strategy, Integer.parseInt(riskStrategy.split(":")[1]));
            }
        }
        return false;
    }

    public static InsurantModel getInsurantModelBySeq(int seq, List<InsurantModel> insurantModelList) {
        for (InsurantModel insurantModel : insurantModelList) {
            if (insurantModel.getInsSeq() == seq) {
                return insurantModel;
            }
        }
        return new InsurantModel();
    }

    public static boolean isSamePerson(InsurantModel insurantModel, AppntModel AppntModel) {
        String insBirthday = DateUtil.format(insurantModel.getBirthday(), "yyyy-MM-dd");
        String appntBirthday = DateUtil.format(AppntModel.getAppntBirthday(), "yyyy-MM-dd");
        return (StringUtils.equals(insurantModel.getName(), AppntModel.getAppntName())
                && StringUtils.equals(insurantModel.getSex(), AppntModel.getAppntSex())
                && StringUtils.equals(insBirthday, appntBirthday)
                && StringUtils.equals(insurantModel.getIdNo(), AppntModel.getIdNo())
                && StringUtils.equals(insurantModel.getIdType(), AppntModel.getIdType()));
    }
    public static boolean isSamePerson(BeneficiaryModel beneficiary, AppntModel AppntModel) {
        String bfcyBirthday = DateUtil.format(beneficiary.getBfcyBirthday(), "yyyy-MM-dd");
        String appntBirthday = DateUtil.format(AppntModel.getAppntBirthday(), "yyyy-MM-dd");
        return (StringUtils.equals(beneficiary.getBfcyName(), AppntModel.getAppntName())
                && StringUtils.equals(beneficiary.getBfcySex(), AppntModel.getAppntSex())
                && StringUtils.equals(bfcyBirthday, appntBirthday)
                && StringUtils.equals(beneficiary.getBfcyIdCode(), AppntModel.getIdNo())
                && StringUtils.equals(beneficiary.getBfcyIdType(), AppntModel.getIdType()));
    }

    public static BigDecimal getAccidentAmount(ProductModel productModel, RequestModel requestModel) {
        BigDecimal amount = BigDecimal.valueOf(0);
        //缴费频次
        String payIntv = requestModel.getProductInfo().getPayIntv();
        BigDecimal prem = productModel.getPrem();
        //非趸交
        if (!StringUtils.equals(payIntv, UnderWriteConstant.SINGLE_PAY)) {
            //年交保费
            prem = prem.multiply(BigDecimal.valueOf(12 / Integer.parseInt(payIntv)));
            //缴费年限
            int payYears = productModel.getPayYear();
            if (StringUtils.equals(StrategyConstant.AGE, productModel.getPayYearFlag())) {
                payYears = payYears - DateUtil.getYears(getInsurantModelBySeq(productModel.getProdInsSeq(), requestModel.getCustInfo().getInsurants().getInsurant()).getBirthday(),
                        requestModel.getPolicyInfo().getPolApplyDate());
            }
            amount = prem.multiply(BigDecimal.valueOf(payYears)).divide(BigDecimal.valueOf(3), 20, BigDecimal.ROUND_HALF_UP);
        }
        return amount;
    }

    public static boolean isAmntRisk(String risk, List<String> risks) {
        for (String configRisk : risks) {
            if (StringUtils.equals(risk, configRisk)) {
                return true;
            }
        }
        return false;
    }

    public static String getCustomerName(CustInfoModel custInfoModel, String idNo) {
        if (StringUtils.equals(custInfoModel.getAppnt().getIdNo(), idNo)) {
            return custInfoModel.getAppnt().getAppntName();
        }
        for (InsurantModel insurant : custInfoModel.getInsurants().getInsurant()) {
            if (StringUtils.equals(insurant.getIdNo(), idNo)) {
                return insurant.getName();
            }
        }
        return "";
    }

    public static boolean isCheckAppntMobilePhone(RequestModel requestModel) {
        AppntModel appntModel = requestModel.getCustInfo().getAppnt();
        if (StringUtils.equals(AgencyConstant.MY0201, requestModel.getPolicyInfo().getAgencyCode())) {
            return false;
        }
        if (appntModel.getAppntNo() == null || StringUtils.equals(appntModel.getAppntNo(), AcceptConstant.MINUS_ONE)) {
            if (StringUtils.isNotBlank(appntModel.getMobile())) {
                return true;
            }
        }
        return false;
    }

    public static String checkIdCardValid(@NonNull PersonModel personModel) {
        if (StringUtils.equals(AcceptConstant.CREDENTIALS_IDNO, personModel.getIdType())) {
            if (!IDCardCheck.checkIDCard(personModel.getIdNo())) {
                return String.format(UnderWriteConstant.UNDERWRITE_ID_CARD_ILLEGAL_MESSAGE, personModel.getName());
            }
            if (personModel.getIdNo().length() == AcceptConstant.IDENTITY_CARD_18) {
                personModel.setIdNo15(IDCardCheck.turnTo15(personModel.getIdNo()));
                personModel.setIdNo18(personModel.getIdNo());
            } else {
                personModel.setIdNo18(IDCardCheck.turnTo18(personModel.getIdNo()));
                personModel.setIdNo15(personModel.getIdNo());
            }
        } else {
            personModel.setIdNo18(personModel.getIdNo());
            personModel.setIdNo15(personModel.getIdNo());
        }
        return null;
    }

    /**
     * String area 时间范围 格式（YYYY-MM-dd|YYYY-MM-dd）
     * Date polApplyDate  表单申请时间
     * 判断当前时间是否是area时间区域内 时间区间
     */
    public static boolean isTimeArea(String area, Date polApplyDate) throws Exception {
        if (StringUtils.isBlank(area)) {
            return false;
        }
        String[] dateTimes = area.split("\\|");

        String begin = dateTimes[0];
        String end = dateTimes[1];
        if (StringUtils.isNotEmpty(begin) && StringUtils.isNotEmpty(end)) {
            LocalDate beginTime = null;
            LocalDate endTime = null;
            try {
                beginTime = LocalDate.parse(begin, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                endTime = LocalDate.parse(end, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            } catch (DateTimeParseException | NullPointerException e) {
                return false;
            }
            LocalDate now = polApplyDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            if (now == null) {
                now = LocalDate.now();
            }
            return !(now.isBefore(beginTime) || now.isAfter(endTime));
        }
        return false;
    }

    /**
     * 判断当前时间是否是area时间区域内 时间区间
     *
     * @param area      时间范围 格式（YYYY-MM-dd|YYYY-MM-dd）or（YYYY-MM-dd|）
     * @param cvalidate 表单生效日期
     * @param riskCode  险种编码
     * @return 返回结果
     * @throws Exception
     */
    public static String isTimeAreaString(String area, Date cvalidate, String riskCode) throws Exception {
        if (StringUtils.isBlank(area)) {
            return AcceptConstant.NOT_EXIST;
        }
        String[] dateTimes = area.split("\\|");
        String begin = dateTimes[0];
        String end = 2 == dateTimes.length ? dateTimes[1] : null;
        if (StringUtils.isNotEmpty(begin)) {
            LocalDate now = cvalidate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            try {
                LocalDate beginTime = LocalDate.parse(begin, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                if (now.isBefore(beginTime)) {
                    return String.format(AcceptConstant.START_DATE_ERROR, riskCode);
                }
                if (StringUtils.isNotBlank(end)) {
                    LocalDate endTime = LocalDate.parse(end, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                    if (now.isAfter(endTime)) {
                        return String.format(AcceptConstant.END_DATE_ERROR, riskCode);
                    }
                }
            } catch (DateTimeParseException | NullPointerException e) {
                throw new Exception("存在未知错误，请查看缓存日期。");
            }
        }
        return AcceptConstant.RESULT_SUCCESS_CODE;
    }
    /**
     * @param jsonObject  json对象
     * @param jsonKey  json的key  若嵌套多层json格式为：xx.xx.xx.xx
     * @return  返回json的value
     */
    public static Object queryJsonValue(String jsonObject, String jsonKey) {
        if (jsonKey == null || jsonObject == null) {
            return null;
        }
        String[] strings = jsonKey.split("\\.");
        Object result = null;
        try {
            JSONObject parseJson = JSON.parseObject(jsonObject);
            for (int i = 0; i < strings.length-1; i++) {
                parseJson = parseJson.getJSONObject(strings[i]);
                if (null == parseJson) {
                    return null;
                }
            }
            result = parseJson.getOrDefault(strings[strings.length - 1], null);
        } catch (Exception e ) {
            e.printStackTrace();
            return null;
        }
        return result;
    }

}
